package com.like.bluetooth.sample.classic

import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import com.like.bluetooth.classic.client.connect.executor.AbstractConnectExecutor
import com.like.bluetooth.classic.client.connect.executor.ConnectExecutorFactory
import com.like.bluetooth.exception.BluetoothException
import com.like.bluetooth.exception.BluetoothExceptionBusy
import com.like.bluetooth.exception.BluetoothExceptionCancelTimeout
import com.like.bluetooth.sample.R
import com.like.bluetooth.sample.databinding.ActivityClassicConnectBinding
import com.like.bluetooth.sample.util.WriteDataFragment
import com.like.bluetooth.util.toHexString
import com.like.common.util.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 连接设备界面
 */
class ClassicConnectActivity : AppCompatActivity() {
    companion object {
        const val KEY_DATA = "data"
    }

    private val mBinding: ActivityClassicConnectBinding by lazy {
        DataBindingUtil.setContentView(this, R.layout.activity_classic_connect)
    }
    private val connectExecutor: AbstractConnectExecutor by lazy {
        val classicScanInfo =
            intent?.getSerializableExtra(KEY_DATA) as? ClassicScanInfo ?: throw UnsupportedOperationException("data is null")
        ConnectExecutorFactory.get(this, classicScanInfo.address).apply {
            onBleOn = {
                if (mBinding.tvConnectStatus.text != "未连接") {
                    val blueColor = ContextCompat.getColor(this@ClassicConnectActivity, R.color.ble_text_blue)
                    mBinding.tvConnectStatus.setTextColor(blueColor)
                    mBinding.tvConnectStatus.text = "蓝牙已打开"
                }
            }
            onBleOff = {
                val redColor = ContextCompat.getColor(this@ClassicConnectActivity, R.color.ble_text_red)
                mBinding.tvConnectStatus.setTextColor(redColor)
                mBinding.tvConnectStatus.text = "蓝牙未打开"
            }
        }
    }
    private val mWriteDataFragment: WriteDataFragment by lazy { WriteDataFragment() }
    private val dataSb = StringBuilder()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding.ivClearLog.setOnClickListener {
            dataSb.clear()
            mBinding.tvData.text = ""
        }
        lifecycleScope.launch(Dispatchers.IO) {
            connectExecutor.setReadCallback().collect {
                appendText("收到数据(${it.size})：${it.toHexString()}")
            }
        }
    }

    private suspend fun appendText(text: String) = withContext(Dispatchers.Main) {
        if (dataSb.isEmpty()) {
            dataSb.append(text)
        } else {
            dataSb.append("\n").append(text)
        }
        mBinding.tvData.text = dataSb
        // 避免scroll在内容还未绘制完毕就滚动，从而滚不到最底部
        mBinding.tvData.post {
            mBinding.sv.fullScroll(View.FOCUS_DOWN)
        }
    }

    fun connect(view: View) {
        val preState = mBinding.tvConnectStatus.text
        mBinding.tvConnectStatus.setTextColor(ContextCompat.getColor(this, R.color.ble_text_blue))
        mBinding.tvConnectStatus.text = "连接中……"

        connectExecutor.connect(lifecycleScope, autoConnectInterval = 3000, onConnected = {
            mBinding.tvConnectStatus.setTextColor(ContextCompat.getColor(this, R.color.ble_text_blue))
            mBinding.tvConnectStatus.text = "连接成功"
        }) {
            when (it) {
                is BluetoothExceptionCancelTimeout -> {
                    // 提前取消超时(BleExceptionCancelTimeout)不做处理。因为这是调用 disconnect() 造成的，使用者可以直接在 disconnect() 方法结束后处理 UI 的显示，不需要此回调。
                }

                is BluetoothExceptionBusy -> {
                    mBinding.tvConnectStatus.setTextColor(ContextCompat.getColor(this, R.color.ble_text_blue))
                    mBinding.tvConnectStatus.text = preState
                    Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
                }

                else -> {
                    mBinding.tvConnectStatus.setTextColor(ContextCompat.getColor(this, R.color.ble_text_red))
                    mBinding.tvConnectStatus.text = it.message
                }
            }
        }
    }

    fun disconnect(view: View) {
        try {
            connectExecutor.disconnect()
            mBinding.tvConnectStatus.setTextColor(ContextCompat.getColor(this, R.color.ble_text_red))
            mBinding.tvConnectStatus.text = "连接断开了"
        } catch (e: BluetoothException) {
            mBinding.tvConnectStatus.setTextColor(ContextCompat.getColor(this, R.color.ble_text_red))
            mBinding.tvConnectStatus.text = e.message
        }
    }

    fun write(view: View) {
        mWriteDataFragment.callback = { data ->
            lifecycleScope.launch {
                try {
                    connectExecutor.write(data)
                    appendText("发送数据(${data.size})：${data.toHexString()}")
                } catch (e: BluetoothException) {
                    onError(e)
                }
            }
        }
        mWriteDataFragment.show(this)
    }

    private suspend fun onError(e: Throwable) {
        withContext(Dispatchers.Main) {
            when (e) {
                is BluetoothExceptionCancelTimeout -> {
                    // 提前取消超时(BleExceptionCancelTimeout)不做处理。因为这是调用 disconnect() 造成的，使用者可以直接在 disconnect() 方法结束后处理 UI 的显示，不需要此回调。
                }

                else -> {
                    Logger.e(e.message)
                }
            }
        }
    }

    override fun onDestroy() {
        connectExecutor.close()
        super.onDestroy()
    }
}